package com.bitnei.battery.service;

import com.bitnei.battery.bean.processBean.ErrorMessage;
import com.bitnei.battery.bean.processBean.MsgData;
import com.bitnei.battery.bean.processBean.ResultMsg;
import com.bitnei.battery.constants.ResultCode;
import com.bitnei.battery.exception.ApiRuntimeException;
import com.bitnei.battery.util.AESUtil;
import com.bitnei.battery.util.HmacUtil;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.json.JsonParser;
import jodd.json.JsonSerializer;
import jodd.util.StringUtil;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author czl
 * @email czl_nylg@163.com
 * @date 2018/6/21 15:25
 * @Version 1.0
 * @Description: Api调用
 */
public class ApiClient {

    //数据加密秘钥
    private String dataKey = null;

    //数据校验秘钥
    private String signKey = null;

    //api请求口令
    private String accessToken = null;


    private static class SingletonHolder{
        private static final ApiClient insatance = new ApiClient();
    }

    private ApiClient(){
    }

    //获取单例
    public static ApiClient getInsatance(){
        return ApiClient.SingletonHolder.insatance;
    }

    /**
     * openService 初始化
     * @param dataKey 数据加密秘钥
     * @param signKey 数据校验私钥
     * @param accessToken api请求口令
     */
    public void init(String dataKey,String signKey,String accessToken){
        if(StringUtils.isEmpty(dataKey) || StringUtils.isEmpty(accessToken))
            throw new ApiRuntimeException("dataKey或accessToke或apiurl 为空!");
        this.dataKey = dataKey;
        this.accessToken = accessToken;
        this.signKey = signKey;
    }

    /**
     * 发送erp请求
     * @param apiUrl 调用service端的请求地址
     * @param reqData 用户请求数据
     */
    public ResultMsg sendApiReq(String apiUrl, Object reqData) throws Exception{
        if(StringUtils.isEmpty(apiUrl) || null == reqData)
            throw new ApiRuntimeException("缺失apiurl参数或请求用户参数！");
        if(StringUtil.isEmpty(dataKey) || StringUtil.isEmpty(accessToken))
            throw new ApiRuntimeException("尚未进行初始化操作！");
        String source = (new JsonSerializer()).deep(true).serialize(reqData);
        //请求并获取响应body
        ResultMsg resultMsg = getResBody(apiUrl, source);
        if(resultMsg.getCode() != ResultCode.OK.getCode())
            return resultMsg;

        //对结果进行解密解析
        Object data = resultMsg.getData();
        if(Objects.isNull(data)) return resultMsg;

        String resData = AESUtil.decrypt(String.valueOf(data), dataKey);
        JsonParser jsonParser = new JsonParser();
        MsgData msgData = jsonParser.parse(resData, MsgData.class);
        resultMsg.setErrMsgList(msgData.getErrorMessages());
        return resultMsg;
    }

    /**
     * 根据url和请求数据获取响应结果
     * @param url 请求url
     * @param source 请求数据
     * @return 返回响应结果body解析对象
     */
    public ResultMsg getResBody(String url,String source){
        //封装对象
        Map<String,Object> reqInfo = new HashMap();
        long timestamp = System.currentTimeMillis();
        reqInfo.put("timestamp",timestamp);
        //数据加密
        reqInfo.putAll(encryptDataStr(source,timestamp));
        //设置请求
        HttpRequest request = HttpRequest.post(url);
        request.header("Authorization", "Bearer " + accessToken);
        request.header("Content-Type", "application/json; charset=utf-8");
        request.body((new JsonSerializer()).serialize(reqInfo));
        //发送
        HttpResponse response = request.send();
        if(response.statusCode() != HttpStatus.OK.value())
            throw new ApiRuntimeException("请求接口异常！错误代码:\t" +  response.statusCode());
        ResultMsg resultMsg = (new JsonParser()).parse(response.body(), ResultMsg.class);
        try {
            resultMsg.setMsg(new String(resultMsg.getMsg().getBytes("iso8859-1"), "utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return resultMsg;
    }


    /**
     * 加密序列化数据
     * 使用client私钥生成数字签名
     * 使用service公钥生加密dataKey
     * @param source 序列化数据
     * @return 返回加密后的序列化数据
     */
    public Map<String,String> encryptDataStr(String source,long timestamp){
        //对序列化数据进行加密
        source = AESUtil.encrypt(source, dataKey);
        Map<String,String> map = new HashMap<>();
        map.put("requestMsg",source);
        try {
            String signDate = "requestMsg" + source + "timestamp" + timestamp;
            if(null == signKey)
                signKey = dataKey;
            String sign = HmacUtil.byteArrayToHexString(HmacUtil.encryptHMAC(signDate.getBytes(), signKey));
            map.put("sign", sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

}
